﻿#light

namespace Langexplr.SwfSupport

[<AbstractClass>]
type SwfTag(number : int) = class
   member this.Number = number
   
end

type FileAttributesTag(hasMetadata:bool,usesAs3:bool,useNetwork:bool) = class
   inherit SwfTag(FileAttributesTag.TagNumber)
   
   override this.ToString() = sprintf "FileAttributesTag(%b,%b,%b)" hasMetadata usesAs3 useNetwork
        
   static member TagNumber = 69
        
   static member ReadFrom(data:byte array):SwfTag =
      
      FileAttributesTag(data.[0] &&& byte(16) <> byte(0),
                        data.[0] &&& byte(8) <> byte(0),
                        data.[0] &&& byte(1) <> byte(0)) :> SwfTag
end

type XmlMetadataTag(xmlMetadata:string) = class
   inherit SwfTag(XmlMetadataTag.TagNumber)
   
   override this.ToString() = sprintf "XmlMetadata(%s...)" (xmlMetadata.Substring(20))
   
   static member TagNumber = 77
   
   static member ReadFrom(data:byte array):SwfTag =
       let (theString,_) = Utils.ReadZeroString(0,data)
       XmlMetadataTag(theString) :> SwfTag
end

type ScriptLimitsTag(maxRecursionDepth:int16,scriptTimeout:int16) = class
   inherit SwfTag(ScriptLimitsTag.TagNumber)
   
   override this.ToString() = sprintf "ScriptLimitsTag(%d,%d)" maxRecursionDepth scriptTimeout
   
   static member TagNumber = 65
   
   static member ReadFrom(data:byte array):SwfTag =
       let recur = int16(data.[0]) ||| int16(data.[1]) <<< 16 in
       let timeout = int16(data.[2]) ||| int16(data.[3]) <<< 16 in
       ScriptLimitsTag(recur,timeout) :> SwfTag
end

type SetBackgroundColorTag(r:byte,g:byte,b:byte) = class
   inherit SwfTag(SetBackgroundColorTag.TagNumber)
   
   override this.ToString() = sprintf "SetBackgroundColorTag(%d,%d,%d)" r g b
   
   static member TagNumber = 9
   
   static member ReadFrom(data:byte array):SwfTag =
       SetBackgroundColorTag(data.[0],data.[1],data.[2]) :> SwfTag
end

type FrameLabelTag(label:string) = class
   inherit SwfTag(FrameLabelTag.TagNumber)
   
   override this.ToString() = sprintf "FrameLabelTag(%s)" label
   
   static member TagNumber = 43
   
   static member ReadFrom(data:byte array):SwfTag =
       FrameLabelTag(System.Text.Encoding.UTF8.GetString(data)) :> SwfTag
end

type ShowFrameTag() = class
   inherit SwfTag(ShowFrameTag.TagNumber)
   
   override this.ToString() = sprintf "ShowFrameTag()" 
   
   static member TagNumber = 1
   
   static member ReadFrom(data:byte array):SwfTag =
       ShowFrameTag() :> SwfTag
end

type DoAbcTag(flags:int,name:string,data:byte array) = class
   inherit SwfTag(DoAbcTag.TagNumber)
   
   member this.Name 
      with get() = name
   
   member this.Data 
      with get() = data
   
   
   override this.ToString() = sprintf "DoAbcTag(%d,%s,%d)" flags name data.Length
   
   static member TagNumber = 82
   
   static member ReadFrom(data:byte array):SwfTag =
       let flags = (int32(data.[0]) ||| int32(data.[1]) <<< 8) |||
                   ((int32(data.[2]) ||| int32(data.[3]) <<< 8) <<< 16 ) in
       let (name,index)  = Utils.ReadZeroString(4,data)       
       DoAbcTag(flags,name,data.[(index+1)..]) :> SwfTag
end

type SymbolClassTag(content: (string * int16) list) = class
   inherit SwfTag(SymbolClassTag.TagNumber)
   
   override this.ToString() = sprintf "SymbolClassTag(%d)" content.Length
   
   static member TagNumber = 76
   
   static member ReadFrom(data:byte array):SwfTag =            
       let (_,content) = Utils.ReadTagStringGroup(0,data)
       SymbolClassTag(content) :> SwfTag
end


type ExportAssetsTag(content: (string * int16) list) = class
   inherit SwfTag(ExportAssetsTag.TagNumber)
   
   override this.ToString() = sprintf "ExportAssetsTag(%d)" content.Length
   
   static member TagNumber = 56
   
   static member ReadFrom(data:byte array):SwfTag =            
       let (_,content) = Utils.ReadTagStringGroup(0,data)
       ExportAssetsTag(content) :> SwfTag
end


type DefineSpriteTag(content: (string * int16) list) = class
   inherit SwfTag(DefineSpriteTag.TagNumber)
   
   override this.ToString() = sprintf "DefineSpriteTag(%d)" content.Length
   
   static member TagNumber = 39
   
   static member ReadFrom(data:byte array):SwfTag =            
       let spriteId = int16(data.[0]) ||| int16(data.[1]) <<< 16 in
       let frameCount = int16(data.[2]) ||| int16(data.[3]) <<< 16 in
       DefineSpriteTag([]) :> SwfTag
end


type UnsupportedTag(number:int,data:byte array ) = class
   inherit SwfTag(number)
   
   override this.ToString() = sprintf "UnsupportedTag(%d,%d)" number data.Length
   
   static member ReadFrom(data:byte array) :SwfTag =      
      UnsupportedTag(-1,data) :> SwfTag
end




type TagSolver() = class
    let solvers = 
        Map.ofList [FileAttributesTag.TagNumber, FileAttributesTag.ReadFrom;
                     XmlMetadataTag.TagNumber, XmlMetadataTag.ReadFrom;
                     ScriptLimitsTag.TagNumber, ScriptLimitsTag.ReadFrom;
                     SetBackgroundColorTag.TagNumber, SetBackgroundColorTag.ReadFrom;
                     FrameLabelTag.TagNumber, FrameLabelTag.ReadFrom;
                     DoAbcTag.TagNumber, DoAbcTag.ReadFrom;
                     SymbolClassTag.TagNumber, SymbolClassTag.ReadFrom;
                     ShowFrameTag.TagNumber, ShowFrameTag.ReadFrom;
                     ExportAssetsTag.TagNumber, ExportAssetsTag.ReadFrom;
                     DefineSpriteTag.TagNumber, DefineSpriteTag.ReadFrom
                     ]

    member this.SolveReaderForTag(tagNumber:int) =
        match solvers.TryFind tagNumber with
           | Some(func) -> func
           | None -> UnsupportedTag.ReadFrom
           
end
